package edu.lehigh.cse.ale;

import org.andengine.audio.music.Music;
import org.andengine.engine.Engine;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.sprite.AnimatedSprite;
import org.andengine.entity.text.Text;
import org.andengine.entity.text.TextOptions;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.font.Font;
import org.andengine.opengl.texture.region.TiledTextureRegion;
import org.andengine.util.HorizontalAlign;

import edu.lehigh.cse.ale.MenuManager.Modes;

public class Splash
{
    /**
     * This is the background music to play, if any
     */
    static Music backgroundMusic;

    /**
     * Draw a splash screen
     * 
     * @param font
     *            The font object to use when creating text
     * 
     * @return A scene that can be drawn by andEngine
     */
    // TODO: it would be nice to remove the need for the font parameter
    static Scene draw(final Font font)
    {
        // create a blank scene
        Scene s = new Scene();
        ALE.reinitCamera();

        // start background music for the main screen
        if (backgroundMusic == null) 
            backgroundMusic = Media.getMusic(Configuration.getMainScreenMusic());
        if (backgroundMusic != null) 
            backgroundMusic.play();

        // draw the background image
        if (!Configuration.getSplashBackground().equals("")) {
            AnimatedSprite as = new AnimatedSprite(0, 0, Configuration.getCameraWidth(),
                    Configuration.getCameraHeight(), Media.getImage(Configuration.getSplashBackground()),
                    ALE._self.getVertexBufferObjectManager());
            s.attachChild(as);
        }

        // Print the name of the game at the top of the scene. You might want a
        // full-screen graphic instead
        Text title = new Text(0, 20, font, Configuration.getTitle(), new TextOptions(HorizontalAlign.CENTER),
                ALE._self.getVertexBufferObjectManager());
        title.setPosition(Configuration.getCameraWidth() / 2 - title.getWidth() / 2, title.getY());
        s.attachChild(title);

        // We're going to print three buttons: "Play", "Help", and "Quit". We could do it by having text that is
        // pressable, or by having custom graphics for each button. The latter looks better, but isn't general for our
        // framework. The former works badly because pressable text doesn't work nicely. Instead, we'll draw text, and
        // then cover it with an invisible image that is pressable. That way, the pressable image will have the desired
        // effect, without needing custom graphics.
        //
        // NB: When debugging, it helps to *not* have invisible images ;)
        //
        // NB: we don't know how wide text is until after we make it, so centering is hard
        //
        // NB: if you prefer, you could make the "play", "help", and "quit" buttons part of the splash image, and then
        // cut out the creation of text in this code and just draw the boxes by hand.

        // cache a few things to make the subsequent code cleaner
        float screenWidth = Configuration.getCameraWidth();

        // draw the "PLAY" button
        Text t = new Text(0, 100, font, Configuration.getPlayButtonText(), new TextOptions(HorizontalAlign.CENTER),
                ALE._self.getVertexBufferObjectManager());
        float w = t.getWidth();
        float x = screenWidth / 2 - w / 2;
        t.setPosition(x, 100);
        s.attachChild(t);
        drawPlayButton(x, 100, w, 40, MenuManager._invis, s, font);

        // only draw a help button if the game has help scenes
        if (Configuration.getHelpScenes() > 0) {
            // create the text
            t = new Text(0, 150, font, Configuration.getHelpButtonText(), new TextOptions(HorizontalAlign.CENTER),
                    ALE._self.getVertexBufferObjectManager());
            w = t.getWidth();
            x = screenWidth / 2 - w / 2;
            t.setPosition(x, 150);
            s.attachChild(t);

            // draw the interactive box
            drawHelpButton(x, 150, w, 40, MenuManager._invis, s);
        }

        // draw the quit button text
        t = new Text(0, 200, font, Configuration.getQuitButtonText(), new TextOptions(HorizontalAlign.CENTER),
                ALE._self.getVertexBufferObjectManager());
        w = t.getWidth();
        x = screenWidth / 2 - w / 2;
        t.setPosition(x, 200);
        s.attachChild(t);

        // draw an invisible interactive box around the quit button to capture touch events
        drawQuitButton(x, 200, w, 40, MenuManager._invis, s);

        return s;
    }

    /**
     * Draw an invisible box, such that touching the box causes the game to end. This is used for the "quit" buton on
     * the main screen
     * 
     * @param x
     *            X coordinate of top left corner of the box
     * @param y
     *            Y coordinate of top left corner of the box
     * @param width
     *            Width of the box
     * @param height
     *            Height of the box
     * @param ttr
     *            The TextureRegion to use
     * @param s
     *            The scene onto which the box should be drawn
     */
    static void drawQuitButton(float x, float y, float width, float height, TiledTextureRegion ttr, Scene s)
    {
        AnimatedSprite as = new AnimatedSprite(x, y, width, height, ttr, ALE._self.getVertexBufferObjectManager())
        {
            @Override
            public boolean onAreaTouched(TouchEvent e, float x, float y)
            {
                if (e.getAction() != TouchEvent.ACTION_DOWN)
                    return false;

                // stop the music
                stopMusic();

                // 'finish' to end this Activity
                ALE._self.finish();
                return true;
            }
        };
        s.attachChild(as);
        s.registerTouchArea(as);
    }

    /**
     * Draw an invisible box, such that touching the box causes the help screen to show. This is used for the "help"
     * buton on the main screen
     * 
     * @param x
     *            X coordinate of top left corner of the box
     * @param y
     *            Y coordinate of top left corner of the box
     * @param width
     *            Width of the box
     * @param height
     *            Height of the box
     * @param ttr
     *            The TextureRegion to use
     * @param s
     *            The scene onto which the box should be drawn
     */
    static void drawHelpButton(float x, float y, float width, float height, TiledTextureRegion ttr, Scene s)
    {
        final Engine _engine = ALE._self.getEngine();
        AnimatedSprite as = new AnimatedSprite(x, y, width, height, ttr, ALE._self.getVertexBufferObjectManager())
        {
            @Override
            public boolean onAreaTouched(TouchEvent e, float x, float y)
            {
                if (e.getAction() != TouchEvent.ACTION_DOWN)
                    return false;

                // stop the music
                if (backgroundMusic != null)
                    backgroundMusic.pause();

                // change modes
                MenuManager._mode = Modes.HELP;
                MenuManager._currLevel = 0;
                _engine.clearUpdateHandlers();
                MenuManager.nextHelp();
                return true;
            }
        };
        s.attachChild(as);
        s.registerTouchArea(as);
    }

    /**
     * Draw an invisible box, such that touching the box causes the level picker to show. This is used for the "play"
     * buton on the main screen
     * 
     * @param x
     *            X coordinate of top left corner of the box
     * @param y
     *            Y coordinate of top left corner of the box
     * @param width
     *            Width of the box
     * @param height
     *            Height of the box
     * @param ttr
     *            The TextureRegion to use
     * @param s
     *            The scene onto which the box should be drawn
     * 
     * @param font
     *            The font to use when drawing the chooser
     */
    static void drawPlayButton(float x, float y, float width, float height, TiledTextureRegion ttr, Scene s,
            final Font font)
    {
        final Engine _engine = ALE._self.getEngine();
        AnimatedSprite as = new AnimatedSprite(x, y, width, height, MenuManager._invis,
                ALE._self.getVertexBufferObjectManager())
        {
            // When this _sprite is pressed, we change the level to 1 and switch
            // to the level picker mode, then we display the appropriate scene
            @Override
            public boolean onAreaTouched(TouchEvent e, float x, float y)
            {
                if (e.getAction() != TouchEvent.ACTION_DOWN)
                    return false;

                // stop the music
                if (backgroundMusic != null)
                    backgroundMusic.pause();

                // change modes
                MenuManager._mode = Modes.CHOOSE;
                MenuManager._currLevel = 1;
                // now draw the chooser screen
                _engine.clearUpdateHandlers();
                // If there is only one level in the game, we return the default level.
                // Luckily, this will also return to the beginning screen when going back
                if (Configuration.getNumLevels() == 1) {
                    ALE._self.configureLevel(1);
                    _engine.setScene(Level._current);
                }
                else {
                    _engine.setScene(Chooser.draw(font));
                }
                return true;
            }
        };
        // put the button and text on the screen, and make the button pressable
        s.attachChild(as);
        s.registerTouchArea(as);
    }

    /**
     * Stop background music that might be playing, and sets it to null
     */
    static void stopMusic()
    {
        if (backgroundMusic != null) {
            backgroundMusic.stop();
            backgroundMusic = null;
        }
    }
}